// Base64Native.cpp
// This project demos how to encode a binary file into BASE64, the most important things are 
// Base64EncodeGetRequiredLength: to get the encoded length to pre allocate memory
// Base64Encode: to perform the encode. The last param has to be ATL_BASE64_FLAG_NOCRLF in order to let encoded PFX file be processed properly by Oobe
//

#pragma once

#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
#include <wincrypt.h>
#include <atlenc.h>
#include <comutil.h>

void Usage()
{
    wprintf(L"Usage: Base64Native [source file] [target file]\r\n");
    exit(0);
}

int _tmain(int argc, _TCHAR* argv[])
{	
    HRESULT hr = S_OK;
    PBYTE pbFileOriginal = NULL;
    PBYTE pbFileFinal = NULL;
    DWORD fileSizeOriginal;
    int fileSizeFinal;
    size_t cchPassword = 0;
    HANDLE hFileSource = INVALID_HANDLE_VALUE;
    HANDLE hFileTarget = INVALID_HANDLE_VALUE;

    if (argc != 3)
    {
        Usage();
    }

    // open the source file
    hFileSource = CreateFile(
        argv[1],
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);

    if (hFileSource == INVALID_HANDLE_VALUE)
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
        goto Exit;
    }

    fileSizeOriginal = GetFileSize(hFileSource, NULL);

    pbFileOriginal = new BYTE[fileSizeOriginal]; 
    if (NULL == pbFileOriginal)
    {
        hr = E_OUTOFMEMORY;
        goto Exit;
    }

    // read in the source file
    if (FALSE == ReadFile(hFileSource, pbFileOriginal, fileSizeOriginal, NULL, NULL))
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
        goto Exit;
    }

    // get the length for BASE64 encode output
    fileSizeFinal = Base64EncodeGetRequiredLength(fileSizeOriginal);

    pbFileFinal = new BYTE[fileSizeFinal];
    if (NULL == pbFileFinal)
    {
        hr = E_OUTOFMEMORY;
        goto Exit;
    }

    // perform the encode
    // last param must be ATL_BASE64_FLAG_NOCRLF so there is no line break, which is the required format for PFX section in prov.xml in WEH8.1
    // http://msdn.microsoft.com/en-us/library/4ad8f0h5(v=vs.80).aspx
    if (FALSE == Base64Encode(pbFileOriginal, fileSizeOriginal, (LPSTR)pbFileFinal, &fileSizeFinal, ATL_BASE64_FLAG_NOCRLF))
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
        goto Exit;
    }

    // create the target file
    hFileTarget = CreateFile(
        argv[2],
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_WRITE,
        NULL,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        NULL);

    // write encoded data to target file
    if (FALSE == WriteFile(hFileTarget, pbFileFinal, fileSizeFinal, NULL, NULL))
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
        goto Exit;
    }

    if (FAILED(SetEndOfFile(hFileTarget)))
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
        goto Exit;
    }

Exit:
    if(hFileSource != INVALID_HANDLE_VALUE)
    {
        CloseHandle(hFileSource);
    }
    if(hFileTarget != INVALID_HANDLE_VALUE)
    {
        CloseHandle(hFileTarget);
    }
    if(pbFileFinal)
    {
        delete []pbFileFinal;
    }
    if(pbFileOriginal)
    {
        delete []pbFileOriginal;
    }

    return (int)hr;
}

